package net.borderwars.userserver;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * @author ehubbard
 *         Date: May 5, 2006
 *         Time: 11:21:15 AM
 */
class InvocationProcessor implements Runnable {
    Invocation ir = null;
    private Attachment at;

    public InvocationProcessor(final Invocation ir, final Attachment at) {
        this.ir = ir;
        this.at = at;
    }

    public void run() {
        Object callOn = null; // if null that means static
        Class callOnClass = ClientConnection.class; // default to calling static methods on Server
        InvocationResult iResult;
        boolean isLogin = true;

        if (ir.getOid().equals(new Integer(-1))) {
            isLogin = true;
        } else {
            isLogin = false;
        }

        if (!isLogin) {
            callOn = at.getClientConnection().getServerSideObject(ir.getOid());
            callOnClass = callOn.getClass();
        }
        try {
            Method m = callOnClass.getMethod(ir.getMethodName(), ir.getTypes());
            Server.log.info("Calling: " + ir.getMethodName());
            Object result = m.invoke(callOn, ir.getArgs());
            if (isLogin) {
                at.setClientConnection((ClientConnection) result);
            }
            result = proxyIfNeeded(result);
            iResult = new InvocationResult(result, ir.getId());

        }
        catch (NoSuchMethodException e) {
            iResult = new InvocationResult(e, ir.getId());
        }
        catch (IllegalAccessException e) {
            iResult = new InvocationResult(e, ir.getId());
        }
        catch (InvocationTargetException e) {
            e.getCause().printStackTrace();
            iResult = new InvocationResult(e.getCause(), ir.getId());
        }

        try {
            at.getSocket().write(Server.makeByteBuffer(iResult));
        }
        catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

    }

    private Object proxyIfNeeded(final Object result) {
        if (result == null) {
            return (null);
        }
        Class cl = result.getClass();
        Class ifs[] = cl.getInterfaces();
        List<Class> toProxy = new LinkedList<Class>();
        for (Class aClass : ifs) {
            if (Server.remoteInterfaces.contains(aClass)) {
                toProxy.add(aClass);
            }
        }
        // if there were no remote interfaces.. just return the result
        if (toProxy.size() == 0) {
            return (result);
        }

        // otherwise store the object in our map, and return an ObjectRef
        ObjectRef or = new ObjectRef(toProxy);
        Integer id = or.getId();
        at.getClientConnection().getObjects().put(id, result);
        return (or);
    }
}
